package com.mt.api.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.mt.common.utils.RedisUtils;
import com.mt.api.constants.constant.JwtConstants;
import com.mt.api.constants.threadlocal.JwtUserThreadLocal;
import com.mt.api.constants.threadlocal.TokenThreadLocal;
import com.mt.api.modules.domain.AppBoss;
import com.mt.api.modules.domain.AppBossBrand;
import com.mt.api.modules.domain.AppBrand;
import com.mt.api.modules.domain.dto.AppBossDto;
import com.mt.api.modules.domain.dto.JwtUserDto;
import com.mt.api.modules.domain.dto.TokenInfoDto;
import com.mt.api.modules.manager.IBossBrandManager;
import com.mt.api.modules.manager.IBrandManager;
import com.mt.api.modules.manager.impl.BossBrandManagerImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Objects;

/**
 * @Author: plover
 * @Date: 2020/07/08/4:03 下午
 * @Description:
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class JwtUserUtils {

    private static IBrandManager brandManager;
    private static RedisUtils redisUtils;
    private static IBossBrandManager bossBrandManager;

    /**
     * token过期时间
     */
    private static final long TOKEN_EXPIRATION_TIME = 60 * 60 * 24 * 30;

    @Autowired
    public void setBrandManager(IBrandManager brandManager) {
        JwtUserUtils.brandManager = brandManager;
    }

    @Autowired
    public void setBossBrandManagerImpl(BossBrandManagerImpl bossBrandManager) {
        JwtUserUtils.bossBrandManager = bossBrandManager;
    }

    @Autowired
    public void setRedisUtils(RedisUtils redisUtils) {
        JwtUserUtils.redisUtils = redisUtils;
    }

    private final static String REDIS_TOKEN_PREFIX_KEY = "token:";
    private final static String REDIS_BOSS_ID_PREFIX_KEY = "boss_id:";
    private final static String REDIS_BOSS_ID_VALID_PREFIX_KEY = "boss_id:valid:";

    public static JwtUserDto getJwtUser() {
        JwtUserDto jwtUserDto = JwtUserThreadLocal.get();
        //解决没有拦截的页面从threadlocal里面取不到user信息
        //解决线程执行，request为nul
        if (Objects.isNull(jwtUserDto) && Objects.nonNull(RequestHolder.getHttpServletRequest())) {
            String token = RequestHolder.getHttpServletRequest().getHeader(JwtConstants.AUTH_HEADER);
            if (StringUtils.isNotEmpty(token)) {
                jwtUserDto = getJwtUserByToken(token);
            }
        }
        return jwtUserDto;
    }

    public static boolean setTokenInfo(String token, JwtUserDto jwtUserDto) {
        //将token存到redis
        redisUtils.set(REDIS_TOKEN_PREFIX_KEY + token, JSON.toJSONString(jwtUserDto), TOKEN_EXPIRATION_TIME);
        redisUtils.set(REDIS_BOSS_ID_PREFIX_KEY + jwtUserDto.getAppBoss().getId(), token, TOKEN_EXPIRATION_TIME);
        return true;
    }

    public static JwtUserDto getJwtUserByToken(String token) {
        String tokenKey = REDIS_TOKEN_PREFIX_KEY + token;
        if (redisUtils.hasKey(tokenKey)) {
            Object object = redisUtils.get(tokenKey);
            return JSON.parseObject(object.toString(), JwtUserDto.class);
        } else {
            //TODO 从数据库查询，然后存入缓存
        }
        return null;
    }

    /**
     * 缓存token信息到redis
     *
     * @param appBoss
     * @return
     */
    public static boolean setRedisTokenInfo(String token, AppBoss appBoss) {
        //缓存token
        if (StringUtils.isNotEmpty(token)) {
            JwtUserDto jwtUserDto = getJwtUserDto(appBoss);
            setTokenInfo(token, jwtUserDto);
        }
        return true;
    }

    public static boolean removeRedisTokenInfo() {
        //缓存token
        String token = TokenThreadLocal.get();
        JwtUserDto jwtUserDto = JwtUserUtils.getJwtUser();
        if (StringUtils.isNotEmpty(token)) {
            redisUtils.del(REDIS_TOKEN_PREFIX_KEY + token, REDIS_BOSS_ID_PREFIX_KEY + jwtUserDto.getAppBoss().getId());
        }
        return true;
    }

    /**
     * 获取账号信息以及品牌信息
     *
     * @param appBoss
     * @return
     */
    private static JwtUserDto getJwtUserDto(AppBoss appBoss) {
        LambdaQueryWrapper<AppBossBrand> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(AppBossBrand::getBossId, appBoss.getId())
                .last("limit 1");
        AppBossBrand appBossBrand = bossBrandManager.getOne(wrapper);

        AppBrand brand = brandManager.getById(appBossBrand.getBrandId());
        JwtUserDto jwtUser = new JwtUserDto();
        jwtUser.setBrand(brand);
        AppBossDto appBossDto = new AppBossDto();
        BeanUtils.copyProperties(appBoss, appBossDto);
        jwtUser.setAppBoss(appBossDto);
        return jwtUser;
    }

    /**
     * 处理登录信息
     *
     * @param appBoss
     * @return
     */
    public static JSONObject handlerLoginInfo(AppBoss appBoss) {
        //生成token
        TokenInfoDto tokenInfoDto = new TokenInfoDto();
        tokenInfoDto.setBossId(appBoss.getId());
        String token = JwtTokenUtil.generateToken(JSON.toJSONString(tokenInfoDto));
        //缓存token
        JwtUserUtils.setRedisTokenInfo(token, appBoss);
        JSONObject result = new JSONObject();
        result.put("token", token);
        return result;
    }

    /**
     * 账号互踢验证，通过账号id与当前登录的token比较
     */
    public static boolean verifyAccountToken(String token) {
        String tokenKey = REDIS_TOKEN_PREFIX_KEY + token;
        if (!redisUtils.hasKey(tokenKey)) {
            log.info("verifyAccountToken redis中token不存在");
            return false;
        }
        JwtUserDto jwtUserDto = getJwtUserByToken(token);
        String idKey = REDIS_BOSS_ID_PREFIX_KEY + jwtUserDto.getAppBoss().getId();
        if (!redisUtils.hasKey(idKey)) {
            log.info("verifyAccountToken redis中用户id不存在");
            return false;
        }
        String redisToken = redisUtils.get(idKey).toString();
        //校验redis中的token与当前请求中的token是否一致,账号互踢 TODO 后面上线打开
        // if (!StringUtils.equals(redisToken, token)) {
        //     return false;
        // }
        return true;
    }

}
